﻿#include "appmonitortaskmanager.h"
#include "dbservice.h"
#include "syscfg.h"
#include "common.h"

AppMonitorTaskManager gAppMonitorTaskManager;

AppMonitorTaskManager::AppMonitorTaskManager()
{

    QString temp = IMPORTANT_APPS;
}

int AppMonitorTaskManager::loadTasksFromDB()
{
    lock.lock();
    SafeClearListAndDelEle(AppMonitorTask, tasks);
    list<AppMonitor *> monitors;
    int ret = gDBService.loadAllAppMonitor(monitors);
    if(ret == f_success)
    {
        foreach (AppMonitor * monitor, monitors) {
            tasks.push_back(new AppMonitorTask(*monitor));
        }

        SafeClearListAndDelEle(AppMonitor, monitors);
    }
    lock.unlock();
    return ret;
}

void AppMonitorTaskManager::startNoStopFlagTasks()
{
    lock.lock();

    foreach (AppMonitorTask * task, tasks) {
        if(task->appMonitor.stopFlag == 0 && task->state == RunableStateStoped)
        {
            task->run();
        }
    }

    lock.unlock();
}

void AppMonitorTaskManager::oneAppMointorDeleted(AppMonitor &monitor)
{
    if(monitor.id >= 0)
    {
        AppMonitorTask * task = NULL;

        for(list<AppMonitorTask *>::iterator iter = tasks.begin(); iter != tasks.end(); iter++)
        {
            if((*iter)->appMonitor.id == monitor.id)
            {
                task = *iter;
                tasks.erase(iter);
                break;
            }
        }


         if(task)
         {
            if(task->state == RunableStateStarted)
            {
                task->stopAndWaitThreadQuit();
            }
            SafeDeleteObj(task);
         }

         else
         {
            tasks.push_back(new AppMonitorTask(monitor));
         }
    }
    else
    {
        LOG_ERROR("monitor's id < 0, invalid");
    }
}

void AppMonitorTaskManager::oneAppMointorUpdated(AppMonitor &monitor)
{
    if(monitor.id >= 0)
    {
         AppMonitorTask * task = getTaskByAppMonitor(monitor);
         if(task)
         {
             if(task->state == RunableStateStarted)
             {
                 task->stopAndWaitThreadQuit();
             }
             task->appMonitor = monitor;
         }
         else
         {
            task = new AppMonitorTask(monitor);
            tasks.push_back(task);
         }

         if(task->appMonitor.stopFlag == 0)
         {
             task->run();
         }
    }
    else
    {
        LOG_ERROR("monitor's id < 0, invalid");
    }
}
AppMonitorTask * AppMonitorTaskManager::getTaskByAppMonitor(const AppMonitor & mointor)
{
    AppMonitorTask * ret = NULL;
    if(mointor.id > 0)
    {
        foreach (AppMonitorTask * task, tasks)
        {
            if(task->appMonitor.id == mointor.id)
            {
                ret = task;
                break;
            }
        }
    }

    return ret;
}

list<AppRunningInfo> AppMonitorTaskManager::getCurrentRunningInfos()
{
    list<AppRunningInfo> ret;
    lock.lock();

    foreach (AppMonitorTask * task, tasks)
    {
        ret.push_back(task->getCurrentRunningInfo());
    }
    lock.unlock();

    return ret;
}

void AppMonitorTaskManager::startTask(AppMonitorTask *task)
{
    LOG_INFO("start task:%s", QStr2CStr(task->appMonitor.name));
    lock.lock();
    task->appMonitor.stopFlag = 0;
    gDBService.saveOneAppMonitor(task->appMonitor);
    if(task->state == RunableStateStoped)
    {
        task->run();
    }
    lock.unlock();
}

void AppMonitorTaskManager::stopAndWaitTask(AppMonitorTask *task,bool stopAppByForce)
{
    lock.lock();
    task->appMonitor.stopFlag = 1;
    gDBService.saveOneAppMonitor(task->appMonitor);
    task->stopAndWaitThreadQuit();
    if(stopAppByForce)
    {
        task->stopAppByForce();
    }
    lock.unlock();
}

int AppMonitorTaskManager::handleAppUpdateReq(AppUpdateReq *req, QString &faileReason)
{
    static int autoIncreaseIndex = 0;
    int index = autoIncreaseIndex;
    autoIncreaseIndex ++;

    LOG_INFO("on app:%s update, update file:%s", req->app.c_str(), req->fileName.c_str());
    int ret = f_success;
    lock.lock();

    AppMonitorTask * task = NULL;
    foreach (AppMonitorTask * temp, tasks)
    {
        if(temp->appMonitor.name.toStdString().compare(req->app) == 0)
        {
            task = temp;
        }
    }

    if (task != NULL)
    {
        bool appRunning = task->isAppRunning();
        QString workPath = task->appMonitor.getWorkPath();
        QString updateFileLocalPath = UPDATE_FILES_STORE_PATH + QString("\\") + QString::fromStdString(req->app)
                + "_" + sayTime(QDateTime::currentDateTime()) + "_" + int2QStr(index);
        CreatDir(QStr2CStr(updateFileLocalPath));

        QString updateFile = updateFileLocalPath + "\\" + QString::fromStdString(req->fileName);
        saveContentToFile(updateFile , req->fileData, req->fileLen);

        if(appRunning)
        {
            LOG_INFO("app is running try to stop it before update");
            task->stopAppByForce();
        }
        else
        {

            LOG_INFO("app is not running, no need to update");
        }


        task->stopAndWaitThreadQuit();


        if(updateFile.endsWith("rar",Qt::CaseInsensitive))
        {
            QString cmd = "WinRAR/Rar.exe e  -y " + updateFile + " \"" + workPath + "\"";

            execCmdWithOutResultEX(new QString(cmd));

            LOG_INFO("update file end with rar, use winrar unpress file:%s to dest:%s", QStr2CStr(updateFile), QStr2CStr(workPath + "\\" +  QString::fromStdString(req->fileName)));
        }
        else
        {
            QString copyTo = workPath + "\\" +  QString::fromStdString(req->fileName);
            LOG_INFO("copy file from：%s， to:%s", QStr2CStr(updateFile), QStr2CStr(copyTo));
            CopyFileA(QStr2CStr(updateFile),QStr2CStr(copyTo),false);
        }
        if(appRunning)
        {
            task->startApp();
        }


        if(task->appMonitor.stopFlag != 1)
        {
            task->start();
        }
    }
    else
    {
        LOG_ERROR("try to update app:%s, but not found", req->app.c_str());
        faileReason = "application not found";
        ret = f_fail;
    }

    lock.unlock();
    return ret;
}

SString AppMonitorTaskManager::getApps()
{
    lock.lock();

    SString ret;
    int index = 0;
    foreach (AppMonitorTask * task, tasks) {

        if(index == 0)
        {
            ret = task->appMonitor.name.toStdString();
        }
        else
        {
            ret += ",";
            ret += task->appMonitor.name.toStdString();
        }

        index++;
    }

    lock.unlock();

    return ret;
}

AppMonitorTask * AppMonitorTaskManager::getTaskByIndex(int index)
{
    if (index <0 || index >= tasks.size())
    {
        return NULL;
    }
    else
    {
        int i = 0;
        foreach (AppMonitorTask * task, tasks) {

            if(i == index)
            {
                return task;
            }
            else
            {
                i++;
            }
        }
    }

    return NULL;
}
